//----------------------------------------------------------------------------------------------
//	Filename:	ShapeFactory.h
//	Author:		Keith Bugeja
//	Date:		27/02/2010
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
#pragma once

#include <iostream>
#include <fstream>

#include <boost/shared_ptr.hpp>

#include "Shape/Shape.h"
#include "Shape/TriangleMesh.h"
#include "Shape/VertexFormats.h"
#include "Material/MaterialGroup.h"

namespace Illumina
{
	namespace Core
	{
		class ShapeForge
		{
		public:
			/*
			template<class TMesh>
			static void SaveMesh(const std::string& p_strMeshFile, boost::shared_ptr<TMesh> p_pMesh)
			{
				int nVertices = p_pMesh->VertexList.Size();
				int nTriangles = p_pMesh->TriangleList.Size();

				std::ofstream meshFile;

				meshFile.open(p_strMeshFile.c_str(), std::ios::binary | std::ios::trunc);

				if (!meshFile.is_open())
				{
					std::cerr << "ERROR -- Couldn't open file \'" << p_strMeshFile << "\'" << std::endl;
				}

				for (int n = 0; n < nVertices; n++)
				{
					meshFile << "v " << p_pMesh->VertexList[n].Position.X << " " <<
						p_pMesh->VertexList[n].Position.Y << " " <<
						p_pMesh->VertexList[n].Position.Z << std::endl;
				}

				for (int n = 0; n < nTriangles; n++)
				{
					meshFile << "f " << (p_pMesh->TriangleList[n].GetVertexIndex(0) + 1) << " " <<
						(p_pMesh->TriangleList[n].GetVertexIndex(1) + 1) << " " <<
						(p_pMesh->TriangleList[n].GetVertexIndex(2) + 1) << std::endl;
				}

				meshFile.close();
			}

			// Quick and dirty obj loader :
			// TODO: Make a ModelIO interface and provide an obj implementation
			template<class TMesh>
			static boost::shared_ptr<TMesh> LoadMesh(const std::string& p_strMeshFile, EngineKernel *p_pEngineKernel, MaterialGroup **p_pMaterialGroup)
			{
				return WavefrontLoader::LoadMesh<TMesh>(p_strMeshFile, p_pEngineKernel, p_pMaterialGroup, false);
			}
			*/

			template<class TMesh>
			static boost::shared_ptr<TMesh> CreateQuad(const Vector3 &p_v0, const Vector3 &p_v1, 
				const Vector3 &p_v2, const Vector3 &p_v3)
			{
				boost::shared_ptr<TMesh> mesh(new TMesh);

				Vertex vertex[4];

				// If vertex has position, initialise
				if (Vertex::GetDescriptor() & VertexFormat::Position)
				{
					vertex[0].Position = p_v0;
					vertex[1].Position = p_v1;
					vertex[2].Position = p_v2;
					vertex[3].Position = p_v3;
				}

				// If vertex has UVs, initialise
				if (Vertex::GetDescriptor() & VertexFormat::UV)
				{
					vertex[0].UV.Set(0,0);
					vertex[1].UV.Set(1,0);
					vertex[2].UV.Set(0,1);
					vertex[3].UV.Set(1,1);
				}

				// Add vertices and faces to mesh
				mesh->AddVertex(vertex[0]);
				mesh->AddVertex(vertex[1]);
				mesh->AddVertex(vertex[2]);
				mesh->AddVertex(vertex[3]);

				mesh->AddIndexedTriangle(0, 2, 1);
				mesh->AddIndexedTriangle(1, 2, 3);

				return mesh;
			}

			static bool CreateQuad(const Vector3 &p_v0, const Vector3 &p_v1, 
				const Vector3 &p_v2, const Vector3 &p_v3, ITriangleMesh *p_pMesh)
			{
				Vertex vertex[4];

				// If vertex has position, initialise
				if (Vertex::GetDescriptor() & VertexFormat::Position)
				{
					vertex[0].Position = p_v0;
					vertex[1].Position = p_v1;
					vertex[2].Position = p_v2;
					vertex[3].Position = p_v3;
				}

				// If vertex has normals, init
				if (Vertex::GetDescriptor() & VertexFormat::Normal)
				{
					Vector3 normal = Vector3::Cross(vertex[2].Position - vertex[0].Position, 
						vertex[1].Position - vertex[0].Position);

					vertex[0].Normal = normal;
					vertex[1].Normal = normal;
					vertex[2].Normal = normal;
					vertex[3].Normal = normal;
				}

				// If vertex has UVs, initialise
				if (Vertex::GetDescriptor() & VertexFormat::UV)
				{
					vertex[0].UV.Set(0,0);
					vertex[1].UV.Set(1,0);
					vertex[2].UV.Set(0,1);
					vertex[3].UV.Set(1,1);
				}

				// Add vertices and faces to mesh
				p_pMesh->AddVertex(vertex[0]);
				p_pMesh->AddVertex(vertex[1]);
				p_pMesh->AddVertex(vertex[2]);
				p_pMesh->AddVertex(vertex[3]);

				p_pMesh->AddIndexedTriangle(0, 2, 1);
				p_pMesh->AddIndexedTriangle(1, 2, 3);

				return true;
			}

			template<class TMesh>
			static boost::shared_ptr<TMesh> CreateBox(const Vector3 &p_minExtent, const Vector3 &p_maxExtent)
			{
				boost::shared_ptr<TMesh> mesh(new TMesh);

				Vertex vertex[24];

				// If vertex has position, initialise
				if (Vertex::GetDescriptor() & VertexFormat::Position)
				{
					vertex[0].Position.Set(p_minExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[1].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[2].Position.Set(p_minExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[3].Position.Set(p_maxExtent.X, p_minExtent.Y, p_maxExtent.Z);

					vertex[4].Position.Set(p_minExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[5].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[6].Position.Set(p_minExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[7].Position.Set(p_maxExtent.X, p_minExtent.Y, p_minExtent.Z);

					vertex[8].Position.Set(p_minExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[9].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[10].Position.Set(p_minExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[11].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_maxExtent.Z);

					vertex[12].Position.Set(p_maxExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[13].Position.Set(p_minExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[14].Position.Set(p_maxExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[15].Position.Set(p_minExtent.X, p_minExtent.Y, p_maxExtent.Z);

					vertex[16].Position.Set(p_minExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[17].Position.Set(p_minExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[18].Position.Set(p_minExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[19].Position.Set(p_minExtent.X, p_maxExtent.Y, p_maxExtent.Z);

					vertex[20].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[21].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[22].Position.Set(p_maxExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[23].Position.Set(p_maxExtent.X, p_minExtent.Y, p_minExtent.Z);
				}

				// If vertex has UVs, initialise
				if (Vertex::GetDescriptor() & VertexFormat::UV)
				{
					for (int nQuadGroup=0; nQuadGroup < 23; nQuadGroup+=4)
					{
						vertex[nQuadGroup + 0].UV.Set(0,0);
						vertex[nQuadGroup + 1].UV.Set(1,0);
						vertex[nQuadGroup + 2].UV.Set(0,1);
						vertex[nQuadGroup + 3].UV.Set(1,1);
					}
				}

				// Add vertices and faces to mesh
				for (int nQuadGroup=0; nQuadGroup < 23; nQuadGroup+=4)
				{
					mesh->AddVertex(vertex[nQuadGroup + 0]);
					mesh->AddVertex(vertex[nQuadGroup + 1]);
					mesh->AddVertex(vertex[nQuadGroup + 2]);
					mesh->AddVertex(vertex[nQuadGroup + 3]);

					mesh->AddIndexedTriangle(nQuadGroup + 0, nQuadGroup + 2, nQuadGroup + 1);
					mesh->AddIndexedTriangle(nQuadGroup + 1, nQuadGroup + 2, nQuadGroup + 3);
				}

				return mesh;
			}

			static bool CreateBox(const Vector3 &p_minExtent, const Vector3 &p_maxExtent, ITriangleMesh *p_pMesh)
			{
				Vertex vertex[24];

				// If vertex has position, initialise
				if (Vertex::GetDescriptor() & VertexFormat::Position)
				{
					vertex[0].Position.Set(p_minExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[1].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[2].Position.Set(p_minExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[3].Position.Set(p_maxExtent.X, p_minExtent.Y, p_maxExtent.Z);

					vertex[4].Position.Set(p_minExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[5].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[6].Position.Set(p_minExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[7].Position.Set(p_maxExtent.X, p_minExtent.Y, p_minExtent.Z);

					vertex[8].Position.Set(p_minExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[9].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[10].Position.Set(p_minExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[11].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_maxExtent.Z);

					vertex[12].Position.Set(p_maxExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[13].Position.Set(p_minExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[14].Position.Set(p_maxExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[15].Position.Set(p_minExtent.X, p_minExtent.Y, p_maxExtent.Z);

					vertex[16].Position.Set(p_minExtent.X, p_minExtent.Y, p_minExtent.Z);
					vertex[17].Position.Set(p_minExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[18].Position.Set(p_minExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[19].Position.Set(p_minExtent.X, p_maxExtent.Y, p_maxExtent.Z);

					vertex[20].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_maxExtent.Z);
					vertex[21].Position.Set(p_maxExtent.X, p_maxExtent.Y, p_minExtent.Z);
					vertex[22].Position.Set(p_maxExtent.X, p_minExtent.Y, p_maxExtent.Z);
					vertex[23].Position.Set(p_maxExtent.X, p_minExtent.Y, p_minExtent.Z);
				}

				// If vertex has UVs, initialise
				if (Vertex::GetDescriptor() & VertexFormat::UV)
				{
					for (int nQuadGroup=0; nQuadGroup < 23; nQuadGroup+=4)
					{
						vertex[nQuadGroup + 0].UV.Set(0,0);
						vertex[nQuadGroup + 1].UV.Set(1,0);
						vertex[nQuadGroup + 2].UV.Set(0,1);
						vertex[nQuadGroup + 3].UV.Set(1,1);
					}
				}

				// Add vertices and faces to mesh
				for (int nQuadGroup=0; nQuadGroup < 23; nQuadGroup+=4)
				{
					p_pMesh->AddVertex(vertex[nQuadGroup + 0]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 1]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 2]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 3]);

					p_pMesh->AddIndexedTriangle(nQuadGroup + 0, nQuadGroup + 2, nQuadGroup + 1);
					p_pMesh->AddIndexedTriangle(nQuadGroup + 1, nQuadGroup + 2, nQuadGroup + 3);
				}

				return true;
			}

			static bool CreateOBB(const Vector3 &p_u, const Vector3 &p_v, const Vector3 &p_w, float p_u_min, float p_u_max, 
																							  float p_v_min, float p_v_max, 
																							  float p_w_min, float p_w_max, ITriangleMesh *p_pMesh)
			{
				
				Vertex vertex[24];

				// If vertex has position, initialise
				if (Vertex::GetDescriptor() & VertexFormat::Position)
				{
					vertex[0].Position.Set(p_u.X*p_u_min + p_v.X*p_v_min + p_w.X*p_w_min, p_u.Y*p_u_min + p_v.Y*p_v_min + p_w.Y*p_w_min, p_u.Z*p_u_min + p_v.Z*p_v_min + p_w.Z*p_w_min);  //0
					vertex[1].Position.Set(p_u.X*p_u_min + p_v.X*p_v_max + p_w.X*p_w_min, p_u.Y*p_u_min + p_v.Y*p_v_max + p_w.Y*p_w_min, p_u.Z*p_u_min + p_v.Z*p_v_max + p_w.Z*p_w_min);  //1
					vertex[2].Position.Set(p_u.X*p_u_min + p_v.X*p_v_max + p_w.X*p_w_max, p_u.Y*p_u_min + p_v.Y*p_v_max + p_w.Y*p_w_max, p_u.Z*p_u_min + p_v.Z*p_v_max + p_w.Z*p_w_max);  //2 
					vertex[3].Position.Set(p_u.X*p_u_min + p_v.X*p_v_min + p_w.X*p_w_max, p_u.Y*p_u_min + p_v.Y*p_v_min + p_w.Y*p_w_max, p_u.Z*p_u_min + p_v.Z*p_v_min + p_w.Z*p_w_max);  //3

					vertex[4].Position.Set(p_u.X*p_u_max + p_v.X*p_v_min + p_w.X*p_w_min, p_u.Y*p_u_max + p_v.Y*p_v_min + p_w.Y*p_w_min, p_u.Z*p_u_max + p_v.Z*p_v_min + p_w.Z*p_w_min);  //4
					vertex[5].Position.Set(p_u.X*p_u_max + p_v.X*p_v_max + p_w.X*p_w_min, p_u.Y*p_u_max + p_v.Y*p_v_max + p_w.Y*p_w_min, p_u.Z*p_u_max + p_v.Z*p_v_max + p_w.Z*p_w_min);  //5
					vertex[6].Position.Set(p_u.X*p_u_max + p_v.X*p_v_max + p_w.X*p_w_max, p_u.Y*p_u_max + p_v.Y*p_v_max + p_w.Y*p_w_max, p_u.Z*p_u_max + p_v.Z*p_v_max + p_w.Z*p_w_max);  //6
					vertex[7].Position.Set(p_u.X*p_u_max + p_v.X*p_v_min + p_w.X*p_w_max, p_u.Y*p_u_max + p_v.Y*p_v_min + p_w.Y*p_w_max, p_u.Z*p_u_max + p_v.Z*p_v_min + p_w.Z*p_w_max);  //7
										
					vertex[8].Position = vertex[0].Position;
					vertex[9].Position = vertex[1].Position;
					vertex[10].Position = vertex[5].Position;
					vertex[11].Position = vertex[4].Position;
					
					vertex[12].Position = vertex[3].Position;
					vertex[13].Position = vertex[2].Position;
					vertex[14].Position = vertex[6].Position;
					vertex[15].Position = vertex[7].Position;

					vertex[16].Position = vertex[1].Position;
					vertex[17].Position = vertex[2].Position;
					vertex[18].Position = vertex[6].Position;
					vertex[19].Position = vertex[5].Position;

					vertex[20].Position = vertex[0].Position;
					vertex[21].Position = vertex[3].Position;
					vertex[22].Position = vertex[7].Position;
					vertex[23].Position = vertex[4].Position;

				}

				// If vertex has UVs, initialise
				if (Vertex::GetDescriptor() & VertexFormat::UV)
				{
					for (int nQuadGroup=0; nQuadGroup < 23; nQuadGroup+=4)
					{
						vertex[nQuadGroup + 0].UV.Set(0,0);
						vertex[nQuadGroup + 1].UV.Set(1,0);
						vertex[nQuadGroup + 2].UV.Set(0,1);
						vertex[nQuadGroup + 3].UV.Set(1,1);
					}
				}

				// Add vertices and faces to mesh
				for (int nQuadGroup=0; nQuadGroup < 7; nQuadGroup+=4)
				{
					p_pMesh->AddVertex(vertex[nQuadGroup + 0]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 1]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 2]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 3]);

					p_pMesh->AddIndexedTriangle(nQuadGroup + 0, nQuadGroup + 1, nQuadGroup + 2);
					p_pMesh->AddIndexedTriangle(nQuadGroup + 0, nQuadGroup + 2, nQuadGroup + 3);
				}

				return true;
			}

			static bool CreateOBBWireFrame(const Vector3 &p_u, const Vector3 &p_v, const Vector3 &p_w, float p_u_min, float p_u_max, 
																							  float p_v_min, float p_v_max, 
																							  float p_w_min, float p_w_max, ITriangleMesh *p_pMesh)
			{
				Vertex corners[8];			
				Vertex vertex[48];
				float quad_b = 0.1f;

				// If vertex has position, initialise
				if (Vertex::GetDescriptor() & VertexFormat::Position)
				{
					corners[0].Position.Set(p_u.X*p_u_min + p_v.X*p_v_min + p_w.X*p_w_min, p_u.Y*p_u_min + p_v.Y*p_v_min + p_w.Y*p_w_min, p_u.Z*p_u_min + p_v.Z*p_v_min + p_w.Z*p_w_min);  //0
					corners[1].Position.Set(p_u.X*p_u_min + p_v.X*p_v_max + p_w.X*p_w_min, p_u.Y*p_u_min + p_v.Y*p_v_max + p_w.Y*p_w_min, p_u.Z*p_u_min + p_v.Z*p_v_max + p_w.Z*p_w_min);  //1
					corners[2].Position.Set(p_u.X*p_u_min + p_v.X*p_v_max + p_w.X*p_w_max, p_u.Y*p_u_min + p_v.Y*p_v_max + p_w.Y*p_w_max, p_u.Z*p_u_min + p_v.Z*p_v_max + p_w.Z*p_w_max);  //2 
					corners[3].Position.Set(p_u.X*p_u_min + p_v.X*p_v_min + p_w.X*p_w_max, p_u.Y*p_u_min + p_v.Y*p_v_min + p_w.Y*p_w_max, p_u.Z*p_u_min + p_v.Z*p_v_min + p_w.Z*p_w_max);  //3

					corners[4].Position.Set(p_u.X*p_u_max + p_v.X*p_v_min + p_w.X*p_w_min, p_u.Y*p_u_max + p_v.Y*p_v_min + p_w.Y*p_w_min, p_u.Z*p_u_max + p_v.Z*p_v_min + p_w.Z*p_w_min);  //4
					corners[5].Position.Set(p_u.X*p_u_max + p_v.X*p_v_max + p_w.X*p_w_min, p_u.Y*p_u_max + p_v.Y*p_v_max + p_w.Y*p_w_min, p_u.Z*p_u_max + p_v.Z*p_v_max + p_w.Z*p_w_min);  //5
					corners[6].Position.Set(p_u.X*p_u_max + p_v.X*p_v_max + p_w.X*p_w_max, p_u.Y*p_u_max + p_v.Y*p_v_max + p_w.Y*p_w_max, p_u.Z*p_u_max + p_v.Z*p_v_max + p_w.Z*p_w_max);  //6
					corners[7].Position.Set(p_u.X*p_u_max + p_v.X*p_v_min + p_w.X*p_w_max, p_u.Y*p_u_max + p_v.Y*p_v_min + p_w.Y*p_w_max, p_u.Z*p_u_max + p_v.Z*p_v_min + p_w.Z*p_w_max);  //7
				
					std::cout << corners[0].Position.ToString() << std::endl;
					std::cout << corners[1].Position.ToString() << std::endl;
					std::cout << corners[2].Position.ToString() << std::endl;
					std::cout << corners[3].Position.ToString() << std::endl;
					std::cout << corners[4].Position.ToString() << std::endl;
					std::cout << corners[5].Position.ToString() << std::endl;
					std::cout << corners[6].Position.ToString() << std::endl;
					std::cout << corners[7].Position.ToString() << std::endl;

					vertex[0].Position = corners[0].Position - p_u*quad_b;
					vertex[1].Position = corners[1].Position - p_u*quad_b;
					vertex[2].Position = corners[1].Position + p_u*quad_b;
					vertex[3].Position = corners[0].Position + p_u*quad_b;

					vertex[4].Position = corners[4].Position - p_u*quad_b;
					vertex[5].Position = corners[5].Position - p_u*quad_b;
					vertex[6].Position = corners[5].Position + p_u*quad_b;
					vertex[7].Position = corners[4].Position + p_u*quad_b;

					vertex[8].Position = corners[1].Position - p_v*quad_b;
					vertex[9].Position = corners[5].Position - p_v*quad_b;
					vertex[10].Position = corners[5].Position + p_v*quad_b;
					vertex[11].Position = corners[1].Position + p_v*quad_b;
					
					vertex[12].Position = corners[0].Position - p_v*quad_b;
					vertex[13].Position = corners[4].Position - p_v*quad_b;
					vertex[14].Position = corners[4].Position + p_v*quad_b;
					vertex[15].Position = corners[0].Position + p_v*quad_b;				

					vertex[16].Position = corners[1].Position - p_v*quad_b;
					vertex[17].Position = corners[2].Position - p_v*quad_b;
					vertex[18].Position = corners[2].Position + p_v*quad_b;
					vertex[19].Position = corners[1].Position + p_v*quad_b;
					
					vertex[20].Position = corners[5].Position - p_v*quad_b;
					vertex[21].Position = corners[6].Position - p_v*quad_b;
					vertex[22].Position = corners[6].Position + p_v*quad_b;
					vertex[23].Position = corners[5].Position + p_v*quad_b;

					vertex[24].Position = corners[2].Position - p_w*quad_b;
					vertex[25].Position = corners[6].Position - p_w*quad_b;
					vertex[26].Position = corners[6].Position + p_w*quad_b;
					vertex[27].Position = corners[2].Position + p_w*quad_b;

					vertex[28].Position = corners[3].Position - p_w*quad_b;
					vertex[29].Position = corners[7].Position - p_w*quad_b;
					vertex[30].Position = corners[7].Position + p_w*quad_b;
					vertex[31].Position = corners[3].Position + p_w*quad_b;

					vertex[32].Position = corners[2].Position - p_w*quad_b;
					vertex[33].Position = corners[3].Position - p_w*quad_b;
					vertex[34].Position = corners[3].Position + p_w*quad_b;
					vertex[35].Position = corners[2].Position + p_w*quad_b;

					vertex[36].Position = corners[6].Position - p_w*quad_b;
					vertex[37].Position = corners[7].Position - p_w*quad_b;
					vertex[38].Position = corners[7].Position + p_w*quad_b;
					vertex[39].Position = corners[6].Position + p_w*quad_b;

					vertex[40].Position = corners[0].Position - p_v*quad_b;
					vertex[41].Position = corners[3].Position - p_v*quad_b;
					vertex[42].Position = corners[3].Position + p_v*quad_b;
					vertex[43].Position = corners[0].Position + p_v*quad_b;

					vertex[44].Position = corners[4].Position - p_v*quad_b;
					vertex[45].Position = corners[7].Position - p_v*quad_b;
					vertex[46].Position = corners[7].Position + p_v*quad_b;
					vertex[47].Position = corners[4].Position + p_v*quad_b;

				}

				// If vertex has UVs, initialise
				if (Vertex::GetDescriptor() & VertexFormat::UV)
				{
					for (int nQuadGroup=0; nQuadGroup < 48; nQuadGroup+=4)
					{
						vertex[nQuadGroup + 0].UV.Set(0,0);
						vertex[nQuadGroup + 1].UV.Set(1,0);
						vertex[nQuadGroup + 2].UV.Set(0,1);
						vertex[nQuadGroup + 3].UV.Set(1,1);
					}
				}

				// Add vertices and faces to mesh
				for (int nQuadGroup=0; nQuadGroup < 48; nQuadGroup+=4)
				{
					p_pMesh->AddVertex(vertex[nQuadGroup + 0]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 1]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 2]);
					p_pMesh->AddVertex(vertex[nQuadGroup + 3]);

					p_pMesh->AddIndexedTriangle(nQuadGroup + 0, nQuadGroup + 1, nQuadGroup + 2);
					p_pMesh->AddIndexedTriangle(nQuadGroup + 0, nQuadGroup + 2, nQuadGroup + 3);
				}				

				return true;
			}

		};
	}
}
